﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml;
using Jerry.DroidBuilder.Common;

namespace Jerry.DroidBuilder.Helpers
{
    public class ResourceReference
    {
        public string Type { get; set; }

        public string Name { get; set; }

        public long Value { get; set; }

        public long UpdatedValue { get; set; }
    }

    public static class UpdateReferenceHelper
    {
        public static IEnumerable<ResourceReference> UpdateReference(string targetDirectory, string originalDefinition, string targetDefinition, bool searchOnly)
        {
            if (!Directory.Exists(targetDirectory))
            {
                throw new Exception("The directory does not exist.");
            }

            const string HEX_NUMBER_PATTERN = "0x([0-9a-f]{5,})";

            var results = new Dictionary<long, ResourceReference>();

            var files = Directory.GetFiles(targetDirectory, "*.smali", SearchOption.AllDirectories);
            var map = new Dictionary<long, List<string>>();

            var originalDocument = new XmlDocument();
            var targetDocument = new XmlDocument();

            originalDocument.Load(originalDefinition);
            targetDocument.Load(targetDefinition);

            foreach (var fileName in files)
            {
                var content = File.ReadAllText(fileName);
                var matches = Regex.Matches(content, HEX_NUMBER_PATTERN, RegexOptions.IgnoreCase);
                var contentUpdated = false;

                foreach (Match match in matches)
                {
                    var value = long.Parse(match.Groups[1].Value, NumberStyles.HexNumber);

                    var onode = originalDocument.SelectSingleNode(string.Format("resources/public[@id='0x{0}']", value.ToString("x8")));

                    if (null != onode)
                    {
                        var item = new ResourceReference
                        {
                            Type = onode.Attributes["type"].Value,
                            Name = onode.Attributes["name"].Value,
                            Value = value
                        };

                        var tnode = targetDocument.SelectSingleNode(string.Format("resources/public[@name='{0}']", onode.Attributes["name"].Value));

                        if (null != tnode)
                        {
                            var tid = tnode.Attributes["id"].Value;
                            var tvalue = long.Parse(tid.Substring(2), NumberStyles.HexNumber);

                            if (tvalue != value)
                            {
                                item.UpdatedValue = tvalue;

                                if (!searchOnly)
                                {
                                    content = content.Replace(match.Value, tid);
                                    contentUpdated = true;
                                }

                                StatusReport.Update(string.Format("Updated type: {0}, name: {1}, id: 0x{2}", tnode.Attributes["type"].Value, tnode.Attributes["name"].Value, tnode.Attributes["id"].Value));
                            }
                        }

                        if (!results.ContainsKey(value))
                        {
                            results.Add(value, item);
                        }
                    }
                }

                if (contentUpdated)
                {
                    File.WriteAllText(fileName, content);
                }
            }

            return results.Values;
        }
    }
}
